#include <pthread.h>	//pthread
#include <stdio.h>	//printf
#include <stdlib.h>	//rand, srand
#include <unistd.h>	//sleep

typedef unsigned int bool;
#define false 0
#define true 1

#define NTHREADS 3
#define NITER 30000

static pthread_barrier_t aaStart, aaPrint, aaVote, aaEnd;
static bool failed = false;
static pthread_mutex_t lock;

void *controlAlg(void *threadId){
	int id = *(int*)(threadId);
	int u = 0;
	int u_safe;
	int n = 0;
	bool fail = false;
	printf("Control Algoritm #%d started...\n", id);
	
	while(n < NITER){
		pthread_barrier_wait(&aaStart);
		printf("CA%d--> It#%d \n", id, n);
		pthread_barrier_wait(&aaPrint);
		u_safe = u;
		if(rand()%10 == 1){
			printf("CA%d--> Alg. failed...\n", id);
			pthread_mutex_lock(&lock);
			failed = true;
			pthread_mutex_unlock(&lock);				
		}else{
			u++;
		}
		
		pthread_barrier_wait(&aaVote);
		pthread_mutex_lock(&lock);
		fail = failed;
		pthread_mutex_unlock(&lock);
		if(fail){
			u = u_safe;
			printf("CA%d--> u_safe = %d\n", id, u_safe);
		}else{
			printf("CA%d--> u = %d\n", id, u);
		}
		
		
		pthread_barrier_wait(&aaEnd);
		pthread_mutex_lock(&lock);
		failed = false;
		pthread_mutex_unlock(&lock);
		
		n++;
		//sleep(1);
	}
	return threadId;
}

int main(){
	pthread_barrier_init(&aaStart, NULL, NTHREADS);
	pthread_barrier_init(&aaPrint, NULL, NTHREADS);
	pthread_barrier_init(&aaVote, NULL, NTHREADS);
	pthread_barrier_init(&aaEnd, NULL, NTHREADS);
	srand(time(NULL));
	pthread_t threadList[NTHREADS];
	
	int i;
	for(i=0;i<NTHREADS;i++){
		pthread_create(&threadList[i], NULL, controlAlg, &i);
	}
	
	for(i=0;i<NTHREADS;i++){
		pthread_join(threadList[i], NULL);
	}
	
	
	return 0;
}
